#!/usr/bin/python
# encoding: utf-8;
# from importlib.resources import path
# from asyncio.windows_events import NULL
import shlex, subprocess
import os
import os.path
import time
import json
import sys

sys.path.append("../..")
from s2c.rules.config import cfg_print_enable, cfg_lsof_filter_fd, cfg_lsof_filter_file


# 执行系统命令并返回打印的信息
def run_cmd(cmd):
    # command_line = "echo 'hello' "
    try:
        # 如果不存在创建表
        if cfg_print_enable: print('run_cmd', cmd)
        args = shlex.split(cmd)
        # output = subprocess.check_output(["python3", "test.py"], shell = False)
        output = subprocess.check_output(args, stderr=subprocess.STDOUT, timeout=30)
        out = output.decode("utf-8")
        return True, out
    except Exception as e:
        # print('run_cmd failed ', str(e))
        return False, str(e)

    '''
    if (out.find("yes") >= 0):
        print("yes")
    else:
        print("no")
    '''


# 执行系统命令并返回打印的信息
def run_cmdb(cmd):
    try:
        if cfg_print_enable: print('run_cmd', cmd)
        file_hix = os.popen(cmd)
        out_str = file_hix.read()
        return True, out_str
    except Exception as e:
        print('run_cmdb failed ', str(e))
        return False, str(e)


# 写一个文件
def write_file(name, strstr):
    print('write_file', strstr)
    file = open(name, mode='w', encoding="utf-8")
    file.write(strstr)
    file.close()


# 读一个文件
def read_file(file):
    ret = ''
    if os.path.exists(file) == False:
        print('read file is not exist', file)
        return False

    try:
        with open(file, 'r', encoding='utf-8') as f:
            ret = f.read()
        f.close()
        return ret
    except Exception as e:
        print('read "' + file + '" file error:', e)
    return False


# 根据文件路径获取文件
def get_filepath(dir_path, list_name):
    """递归获取目录下（文件夹下）所有文件的路径"""
    for file in os.listdir(dir_path):  # 获取文件（夹）名
        file_path = os.path.join(dir_path, file)  # 将文件（夹）名补全为路径
        if os.path.isdir(file_path):  # 如果是文件夹，则递归
            get_filepath(file_path, list_name)
        else:
            list_name.append(file_path)  # 保存路径
    return list_name


# 字符串查找和关键字截取
# strstr 需要处理的字符串
# keyword_str 需要查找的关键字
# keyword_end 关键字后面字符串的结束字符，默认以\n
def search_keyword(strstr, keyword_str, keyword_end='\n', strtrim=True):
    # keyword_str = 'ID='
    # keyword_end = '\n'
    index = strstr.find(keyword_str)
    if index == -1:
        return ''
    tmp = strstr[index + len(keyword_str):len(strstr)]
    strlist = tmp.split(keyword_end)
    # print('===strlist==', strlist)
    # 如果需要清理字符串的前后特殊字符，可以使用strstr.strip()
    if (strtrim):
        return strlist[0].strip()

    return strlist[0]


# 判断一个数组是否已经存在
def check_arr_exist(arr, key):
    for item in arr:
        if item == key:
            return True
    return False


# 获取文件路径的上一层目录
def get_path_parent(path):
    # 先判断最后一个字符串是否为/,如果是先过滤掉
    out_str = path
    # 判断最后一个字符是否为/
    if path[-1] == '/':
        out_str = path[0: len(path) - 1]
    index = out_str.rfind('/')
    out_str = out_str[0: index]
    return out_str


# 根据文件路径判断该文件是否存在软连接文件，并返回所有软连接的文件路径
def get_path_lns(path):
    # path = '/usr/lib64/libfontconfig.so.1.12.0'
    # 先取出文件名称
    dir, file = os.path.split(path)
    end = file.find('.')
    file_name = file[0: end]
    # data = read_file('debug.log')
    status, data = run_cmdb('ls -ls ' + dir + '/' + file_name + '*')
    if status == False:
        return []
    # print('======get_path_lns==========', data)
    strArr = data.split('\n')
    ret_arr = [path]
    for linestr in strArr:
        linestr = linestr.strip()
        if len(linestr) < 1:
            continue
        index = linestr.find('->')
        if index < 0:
            index_start = linestr.find('/')
            # 如果没有找到/表示不是路径
            if index_start == -1:
                continue
            file_path = linestr[index_start: len(linestr)]
            file_path = file_path.strip()
            # 在取消掉结束为:的字符
            file_path = file_path.strip(':')
            if check_arr_exist(ret_arr, file_path) == False:
                ret_arr.append(file_path)
            continue
        # 如果有软连接文件，进行分离解析
        index_start = linestr.find('/')
        temp_file = linestr[index_start: len(linestr)]
        file_arr = temp_file.split('->')
        file_path = file_arr[0].strip()
        if check_arr_exist(ret_arr, file_path) == False:
            ret_arr.append(file_path)
    return ret_arr


# 根据服务名称判断是否有满足该服务的文件名称
def get_path_file(path):
    # data = read_file('httpdserver.log')
    status, data = run_cmdb('ls -ls ' + path + '*')
    if status == False:
        return []
    print('======get_path_file==========', data)
    strArr = data.split('\n')
    ret_arr = []
    for linestr in strArr:
        linestr = linestr.strip()
        if len(linestr) < 1:
            continue
        index = linestr.find('->')
        if index < 0:
            index_start = linestr.find('/')
            # 如果没有找到/表示不是路径
            if index_start == -1:
                continue
            file_path = linestr[index_start: len(linestr)]
            file_path = file_path.strip()
            # 在取消掉结束为:的字符
            file_path = file_path.strip(':')
            if check_arr_exist(ret_arr, file_path) == False:
                ret_arr.append(file_path)
            continue
        # 如果有软连接文件，进行分离解析
        index_start = linestr.find('/')
        temp_file = linestr[index_start: len(linestr)]
        file_arr = temp_file.split('->')
        file_path = file_arr[0].strip()
        if check_arr_exist(ret_arr, file_path) == False:
            ret_arr.append(file_path)
    return ret_arr


# 读取字典json文件并返回数组
def get_json_file(file_name):
    # 打开文件
    with open(file_name, 'r') as f:
        data_obj = json.load(f)
    return data_obj


# 根据行数据解析出关键字
def analysis_transplant_line(strstr):
    index = strstr.find('/')
    # 如果找到/表示带路径
    if index > 0:
        # 结束]字符需要过滤掉，总长度减一, 起始地址需要在加一，过滤掉[
        out_str = strstr[index: len(strstr)].strip()
        cont = out_str.find(' ')
        if cont > 0:
            # 如果找到空格说明还需要进行拆分，如格式： /usr/sbin/nginx (path inode=25207998)
            tmp_arr = out_str.split(' ')
            out_str = tmp_arr[0]
        return out_str
    return ''


# 根据文件路径，获取路径指定的目录层
def get_parent_path(path, level=1):
    parent_path = path
    # 如果传入的路径没有/直接返回该路径
    if parent_path.find('/') == -1:
        return parent_path

    ret_path = '/'
    for i in range(level):
        parent_path = parent_path.strip('/')
        index = parent_path.find('/')
        if index == -1:
            return ret_path
        else:
            ret_path += parent_path[0: index] + '/'
            parent_path = parent_path[index: len(parent_path)]

    return ret_path


# 根据APP名称获取是否有监听端口
def get_service_port(name):
    status, data = run_cmd('netstat -tunlp')
    if status == False:
        return []
    # data = read_file('port.log')
    ret_port = []
    if data is None:
        return ret_port
    str_arr = data.split('\n')
    for line_str in str_arr:
        index = line_str.find(name)
        # 查找服务名称
        if index == -1:
            continue
        # 状态是listen状态
        index = line_str.find('LISTEN')
        if index == -1:
            continue
        # 分解port信息
        line_arr = line_str.split(' ')
        # print('==============' , line_arr)
        # 保留有:字符的数据
        for tmp_str in line_arr:
            tmp_str = tmp_str.strip()
            if tmp_str == '':
                continue
            if tmp_str.find(':') > -1:
                # tmp_arr.append(tmp_str)
                tmp_arr = tmp_str.split(':')
                for port in tmp_arr:
                    port = port.strip()
                    # print('---------------', port)
                    if port.isdigit():
                        ret_port.append(port)

    # 对数组进行去重操作
    return list(set(ret_port))


# 解析服务依赖或者打开的相关文件
def analysis_lsof_str(line):
    ret_arr = []
    tmp = ''
    for file_type in cfg_lsof_filter_fd:
        # 查找服务需要提取的数据
        tmp = search_keyword(line, file_type)
        if tmp != '':
            break
    # 如果未找到获取的数据，直接返回空数组
    if tmp == '':
        return ret_arr
    path = analysis_transplant_line(tmp)
    print('===========analysis_lsof_str==============', path)
    if path != '' and check_arr_exist(cfg_lsof_filter_file, path) == False:
        ret_arr.append(path)
        # 根据文件路径检查是否有相同文件的软连接文件
        ln_arr = get_path_lns(path)
        # 如果数组大于1，进行拼接操作
        if len(ln_arr) > 1:
            ret_arr.extend(ln_arr)

    # 返回路径和文件数组
    return ret_arr


# 根据毫秒数返回时间字符串
def format_time(millisecond):
    ret_millisecond = int(millisecond)  # 毫秒
    ret_second = 0  # 秒
    ret_minute = 0  # 分
    ret_hour = 0  # 小时

    # 如果毫秒数大于1000，将毫秒数转换成整数
    if (ret_millisecond >= 1000):
        # 获取秒数，除1000取整，得到秒数，余数为毫秒
        ret_second = ret_millisecond // 1000
        ret_millisecond = ret_millisecond % 1000

    # 获取分钟，除以60取整数，得到整数分钟
    if ret_second >= 60:
        ret_minute = ret_second // 60
        ret_second = ret_second % 60

    # 如果分钟大于60，将分钟转换成小时
    if ret_minute >= 60:
        # 获取小时，获取分钟除以60，得到整数小时
        ret_hour = ret_minute // 60
        ret_minute = ret_minute % 60

    if ret_hour > 0:
        result = str(ret_hour) + '时,' + str(ret_minute) + '分,' + str(ret_second) + '秒,' + str(ret_millisecond) + '毫秒'
    elif ret_minute > 0:
        result = str(ret_minute) + '分,' + str(ret_second) + '秒,' + str(ret_millisecond) + '毫秒'
    elif ret_second > 0:
        result = str(ret_second) + '秒,' + str(ret_millisecond) + '毫秒'
    else:
        result = str(ret_millisecond) + '毫秒'

    return result


# 获取当前系统时间，并格式输出
def get_system_date_time():
    now = int(time.time())  # ->这是时间戳
    timeArray = time.localtime(now)
    return time.strftime("%Y-%m-%d %H:%M:%S", timeArray)


# 判断对象的字段是否存在
def check_obj_key(obj, key):
    try:
        # 只要key字段存在就然后TRUE，不管内容
        if obj[key]:
            return True
        return True
    except Exception as e:
        # error: has not attribute
        print(key + ' key is not exist', obj)
    return False


# 判断数组的value是否存在
def check_arr_key(arr, key):
    for value in arr:
        if value == key:
            return True
    return False


#  man 方法
def main():
    print("Hello, utils!")
    # ret = format_time(0)
    # tmp = get_path_parent('/usr/lib64/')
    # print(ret)
    # arr = ['/usr/lib64/liblua-5.3.so', '/usr/lib64/httpd/modules/mod_access_compat.so', '/usr/lib64/libaprutil-1.so.0', '/usr/lib64/httpd/modules/mod_dav_fs.so', '/usr/lib64/libnghttp2.so.14.17.0', '/usr/lib64/httpd/modules/mod_authn_dbm.so', '/usr/lib64/httpd/modules/mod_proxy_http2.so', '/usr/lib64/libz.so.1', '/usr/lib64/httpd/modules/mod_reqtimeout.so', '/usr/lib64/libblkid.so.1', '/usr/lib64/httpd/modules/mod_authn_core.so', '/usr/lib64/httpd/modules/mod_authz_dbm.so', '/usr/lib64/libgpg-error.so.0', '/usr/lib64/httpd/modules/mod_unixd.so', '/usr/lib64/libexpat.so.1.6.7', '/usr/lib64/libpcre2-16.so.0.7.1', '/usr/lib64/httpd/modules/mod_request.so', '/usr/lib64/libpcre2-16.so.0', '/usr/lib64/libcrypto.so.1.1', '/usr/lib64/libbrotlienc.so.1', '/usr/lib64/libpcre2-16.so', '/usr/lib64/libpcre2-32.so.0.7.1', '/usr/lib64/httpd/modules/mod_authz_dbd.so', '/usr/sbin/httpd', '/usr/lib64/httpd/modules/mod_lbmethod_bybusyness.so', '/usr/lib64/httpd/modules/mod_authz_core.so', '/usr/lib64/httpd/modules/mod_logio.so', '/usr/lib64/httpd/modules/mod_echo.so', '/usr/lib64/liblzma.so', '/usr/lib64/httpd/modules/mod_setenvif.so', '/usr/lib64/libapr-1.la', '/usr/lib64/httpd/modules/mod_expires.so', '/usr/lib64/libexpat.so', '/usr/lib64/httpd/modules/mod_dav_lock.so', '/usr/lib64/httpd/modules/mod_proxy_ftp.so', '/usr/lib64/libcryptsetup.so.12', '/usr/lib64/libbrotlicommon.so.1', '/usr/lib64/libpcre2-8.so.0.7.1', '/usr/lib64/librt-2.28.so', '/usr/lib64/libbrotlicommon.so.1.0.6', '/usr/lib64/ld-2.28.so', '/usr/lib64/httpd/modules/mod_lbmethod_byrequests.so', '/usr/lib64/libpcreposix.so.0', '/usr/lib64/httpd/modules/mod_watchdog.so', '/usr/lib64/httpd/modules/mod_cache_socache.so', '/usr/lib64/libnss_myhostname.so.2', '/usr/lib64/httpd/modules/mod_auth_basic.so', '/usr/lib64/libselinux.so', '/usr/lib64/httpd/modules/mod_log_config.so', '/usr/lib64/libapr-1.so', '/usr/lib64/httpd/modules/mod_cache.so', '/usr/lib64/httpd/modules/mod_status.so', '/usr/lib64/httpd/modules/mod_lbmethod_bytraffic.so', '/usr/lib64/libdl-2.28.so', '/usr/lib64/httpd/modules/mod_socache_shmcb.so', '/usr/lib64/libpcreposix.so.0.0.6', '/usr/lib64/libaprutil-1.so', '/usr/lib64/httpd/modules/mod_vhost_alias.so', '/usr/lib64/libgcc_s-8-20210514.so.1', '/usr/lib64/httpd/modules/mod_remoteip.so', '/usr/lib64/libcap.so.2', '/usr/lib64/libnss_systemd.so.2', '/usr/lib64/libpcre2-32.so', '/usr/lib64/httpd/modules/mod_suexec.so', '/usr/lib64/httpd/modules/mod_proxy_balancer.so', '/usr/lib64/liblz4.so.1.8.3', '/usr/lib64/liblzma.so.5', '/usr/lib64/libresolv-2.28.so', '/usr/lib64/httpd/modules/mod_data.so', '/usr/lib64/httpd/modules/mod_brotli.so', '/usr/lib64/httpd/modules/mod_allowmethods.so', '/usr/lib64/libgpg-error.so', '/usr/lib64/httpd/modules/mod_authn_anon.so', '/usr/lib64/liblz4.so.1', '/usr/lib64/httpd/modules/mod_proxy_hcheck.so', '/usr/lib64/libcrypto.so.1.1.1k', '/usr/lib64/httpd/modules/mod_proxy_express.so', '/usr/lib64/libcrypt.so.1.1.0', '/usr/lib64/libcrypto.so', '/usr/lib64/libpcre2-posix.so.2', '/usr/lib64/httpd/modules/mod_slotmem_shm.so', '/usr/lib64/libz.so', '/usr/lib64/httpd/modules/mod_unique_id.so', '/usr/lib64/httpd/modules/mod_dbd.so', '/usr/lib64/httpd/modules/mod_authz_owner.so', '/usr/lib64/httpd/modules/mod_alias.so', '/usr/lib64/httpd/modules/mod_proxy_wstunnel.so', '/usr/lib64/libgpg-error.so.0.24.2', '/usr/lib64/httpd/modules/mod_systemd.so', '/usr/lib64/libgcrypt.so.20', '/usr/lib64/libmount.so.1.1.0', '/usr/lib64/httpd/modules/mod_dav.so', '/usr/lib64/httpd/modules/mod_http2.so', '/usr/lib64/httpd/modules/mod_macro.so', '/usr/lib64/httpd/modules/mod_actions.so', '/usr/lib64/libapr-1.so.0.6.3', '/usr/lib64/httpd/modules/mod_authz_groupfile.so', '/usr/lib64/httpd/modules/mod_lbmethod_heartbeat.so', '/usr/lib64/httpd/modules/mod_dir.so', '/usr/lib64/httpd/modules/mod_authn_dbd.so', '/usr/lib64/httpd/modules/mod_slotmem_plain.so', '/usr/lib64/libz.so.1.2.11', '/usr/lib64/libuuid.so.1.3.0', '/usr/lib64/httpd/modules/mod_filter.so', '/usr/lib64/libcap-ng.so.0', '/usr/lib64/httpd/modules/mod_deflate.so', '/usr/lib64/libpcre2-posix.so', '/usr/lib64/httpd/modules/mod_env.so', '/usr/lib64/httpd/modules/mod_auth_digest.so', '/usr/lib64/libaprutil-1.la', '/usr/lib64/libnss_sss.so.2', '/usr/lib64/httpd/modules/mod_proxy_http.so', '/usr/lib64/libblkid.so.1.1.0', '/usr/lib64/libzstd.so.1.4.4', '/usr/lib64/httpd/modules/mod_proxy_ajp.so', '/usr/lib64/httpd/modules/mod_socache_memcache.so', '/usr/lib64/httpd/modules/mod_mime_magic.so', '/usr/lib64/libapr-1.so.0', '/usr/lib64/libcrypt.so.1', '/usr/lib64/libpcre2-8.so', '/usr/lib64/httpd/modules/mod_authz_host.so', '/usr/lib64/libm-2.28.so', '/usr/lib64/libmount.so.1', '/usr/lib64/httpd/modules/mod_mime.so', '/usr/lib64/libgcrypt.so.20.2.5', '/usr/lib64/libsystemd.so.0.23.0', '/usr/lib64/libsystemd.so.0', '/usr/lib64/httpd/modules/mod_proxy_connect.so', '/usr/lib64/httpd/modules/mod_cgid.so', '/usr/lib64/httpd/modules/mod_proxy_uwsgi.so', '/usr/lib64/libc-2.28.so', '/usr/lib64/libpcre.so.1', '/usr/lib64/httpd/modules/mod_authn_socache.so', '/usr/lib64/libpcre.so.1.2.10', '/usr/lib64/httpd/modules/mod_lua.so', '/usr/lib64/httpd/modules/mod_proxy_scgi.so', '/usr/lib64/libaprutil-1.so.0.6.1', '/usr/lib64/httpd/modules/mod_version.so', '/usr/lib64/libuuid.so.1', '/usr/lib64/httpd/modules/mod_mpm_event.so', '/usr/lib64/httpd/modules/mod_socache_dbm.so', '/usr/lib64/httpd/modules/mod_authn_file.so', '/usr/lib64/libcryptsetup.so.12.6.0', '/usr/lib64/libpcre2-8.so.0', '/usr/lib64/httpd/modules/mod_negotiation.so', '/usr/lib64/httpd/modules/mod_rewrite.so', '/usr/lib64/libpcre2-32.so.0', '/usr/lib64/libnss_files-2.28.so', '/usr/lib64/libgcrypt.so', '/usr/lib64/httpd/modules/mod_cache_disk.so', '/usr/lib64/httpd/modules/mod_authz_user.so', '/usr/lib64/libexpat.so.1', '/usr/lib64/libnghttp2.so.14', '/usr/lib64/httpd/modules/mod_ext_filter.so', '/usr/lib64/libzstd.so.1', '/usr/lib64/httpd/modules/mod_headers.so', '/usr/lib64/libnss_dns-2.28.so', '/usr/lib64/httpd/modules/mod_autoindex.so', '/usr/lib64/liblzma.so.5.2.4', '/usr/lib64/libpcre2-posix.so.2.0.1', '/usr/lib64/httpd/modules/mod_proxy.so', '/usr/lib64/httpd/modules/mod_dumpio.so', '/usr/lib64/libcap.so.2.26', '/usr/lib64/httpd/modules/mod_userdir.so', '/usr/lib64/httpd/modules/mod_include.so', '/usr/lib64/libbrotlienc.so.1.0.6', '/usr/lib64/libselinux.so.1', '/usr/lib64/httpd/modules/mod_substitute.so', '/usr/lib64/libpthread-2.28.so', '/usr/lib64/libcap-ng.so.0.0.0', '/usr/lib64/httpd/modules/mod_proxy_fcgi.so', '/usr/lib64/httpd/modules/mod_proxy_fdpass.so', '/usr/lib64/httpd/modules/mod_info.so']
    # print(tmp)
    # print('-------------', ddd)
    # os.system('rm -rf ' + cfg_docker_path_tmp)


if __name__ == "__main__":
    main()
